#ifndef _NAND_W25N_H
#define _NAND_W25N_H

#include "nand_spi.h"
//////////////////////////////////////////////////////////////////////////////////
// 状态描述：
// OPT-E  : 控制读写命名操作的是主存储区或者OPT存储区
// P_FAIL : 编程失败 - 编程地址无效或者区域受保护 - 执行编程或者执行RESET清零
// E_FAIL : 擦除失败 - 擦除地址无效或者区域受保护 - 执行擦除或者执行RESET清零 
// WEL    : 写使能   - 1=enable, 0=disable, 执行编程或擦除指令时会自动清除WEL
// OIP    ：忙状态   - 读页，执行编程，擦除，reset后进入忙状态
// 
// ECCS1---ECCS0---
// 0       0    ---No bit errors were detected during the previous read algorithm
// 0       1    ---Bit errors(<4) were detected and corrected
// 1       0    ---Bit errors greater than ECC capability(8 bits) and not corrected
// 1       1    ---Bit errors reach ECC capability( 8 bits) and not corrected
//////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
* @brief   FLASH INFO
*****************************************************************************/
/*
#define W25N_PAGE_MAIN_SIZE               2048
#define W25N_PAGE_SPARE_SIZE              64
#define W25N_PAGE_SIZE                    (W25N_PAGE_MAIN_SIZE + W25N_PAGE_SPARE_SIZE)
#define W25N_PAGE_PER_BLOCK               64
#define W25N_BLOCK_TOTAL                  1024
*/

#define NAND_ST_BUSY_MASK				  0x01
#define NAND_ST_WREN_MASK				  0x02
#define NAND_ST_ECC_MASK				  0x30

/*****************************************************************************
* @brief   CMD LIST
*****************************************************************************/
#define NAND_CMD_WRITE_ENABLE             0x06
#define NAND_CMD_WRITE_DISABLE            0x04

#define NAND_CMD_FEATURE_GET              0x0F
#define NAND_CMD_FEATURE_SET              0x1F

#define NAND_FEATURE_1_PROTECT            0xA0  //Ax
#define NAND_FEATURE_2_CFG                0xB0  //Bx  
#define NAND_FEATURE_3_ST                 0xC0  //Cx

#define NAND_CMD_READ_ID                  0x9F                  

#define NAND_CMD_PAGE_READ                0x13  //read page to cache
#define NAND_CMD_CACHE_READ               0x03  //read data from cache
#define NAND_CMD_CACHE_READ_FAST          0x0B  //read data from cache
#define NAND_CMD_CACHE_READ_X4            0x6B  //read data from cache //cmd and addr is spi, data is qspi

#define NAND_CMD_PROGRAM_LOAD             0x02  //写cache，未写的部分会被填充为0xFF
#define NAND_CMD_PROGRAM_LOAD_X4          0x32  //写cache，未写的部分会被填充为0xFF //cmd and addr is spi, data is qspi

#define NAND_CMD_PROGRAM_EXE              0x10  //将cache写入nand

#define NAND_CMD_PROGRAM_LOAD_RANDOM      0x84  //写cache，未写的部分保持不变
#define NAND_CMD_PROGRAM_LOAD_RANDOM_X4   0x34  //写cache，未写的部分保持不变

#define NAND_CMD_BLOCK_ERASE              0xD8

#define NAND_CMD_RESET                    0xFF

/*****************************************************************************
* @brief   STRUCT
*****************************************************************************/
typedef struct
{
	uint16_t page_main_size;
	uint16_t page_spare_size;
	uint16_t page_per_block;
	uint16_t block_total;
	uint8_t	 dev_st;				//busy 等待时，FEATURE_3_ST 读取值
	volatile uint8_t  tick;
} nand_info_type;

extern nand_info_type spi_nand_info;

/*****************************************************************************
* @brief   NAND-FLASH COMMON API
*****************************************************************************/
void spi_nand_reset(void);

uint8_t spi_nand_featute_get(uint8_t reg_addr);
uint8_t spi_nand_featute_set(uint8_t reg_addr, uint8_t msk, uint8_t dat);

uint8_t spi_nand_wait_ready(void);

uint8_t spi_nand_ecc_error_get(void);

uint8_t spi_nand_write_enable(void);
uint8_t spi_nand_write_disable(void);

void spi_nand_read_id(uint8_t *dat);

/* read and write */
uint8_t spi_nand_read_page(uint32_t page_addr);

uint8_t spi_nand_read_cache(uint16_t coil_addr, uint8_t * dat, uint16_t Len);
uint8_t spi_nand_q_read_cache(uint16_t coil_addr, uint8_t * dat, uint16_t Len);

uint8_t spi_nand_write_cache(uint16_t coil_addr, const uint8_t * dat, uint16_t Len);		// clear cache and write dat 
uint8_t spi_nand_random_write_cache(uint16_t addr, const uint8_t * dat, uint16_t Len);	// keep cache and write dat
uint8_t spi_nand_q_write_cache(uint16_t coil_addr, const uint8_t * dat, uint16_t Len);
uint8_t spi_nand_q_random_write_cache(uint16_t addr, const uint8_t * dat, uint16_t Len);

uint8_t spi_nand_program_exe(uint32_t page_addr);

/* erase */
uint8_t spi_nand_block_erase(uint32_t block_addr);
uint8_t spi_nand_chip_erase(void);

/* auto cmd */
void spi_nand_cmd_signal_exe(uint8_t cmd);
uint8_t spi_nand_cmd_exe(uint8_t cmd, uint8_t par);
uint8_t spi_nand_cmd_auto(const uint8_t *send, uint8_t send_len, uint8_t *rcv, uint8_t rcv_cnt);

/*****************************************************************************
* @brief   SPECIAL API for W25N
*****************************************************************************/
uint8_t w25n_opt_mem_select(void);
uint8_t w25n_main_mem_select(void);
uint8_t w25n_init(void);

/*****************************************************************************
* @brief   SPECIAL API for GD5
*****************************************************************************/
uint8_t gd5_opt_mem_select(void);
uint8_t gd5_main_mem_select(void);
uint8_t gd5_init(void);

#endif
